﻿//SmartCandleManagerSource.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Smart
{
	using System;
	using System.Collections.Generic;
	using System.Linq;

	using Ecng.Collections;
	using Ecng.Common;
	using Ecng.ComponentModel;

	using StockSharp.Algo.Candles;
	using StockSharp.BusinessEntities;

	/// <summary>
	/// SmartCOM источник свечек типа <see cref="TimeFrameCandle"/>.
	/// </summary>
	public class SmartCandleManagerSource : Disposable, ICandleManagerSource
	{
		private readonly SynchronizedPairSet<Tuple<Security, SmartTimeFrames>, CandleSeries> _series = new SynchronizedPairSet<Tuple<Security, SmartTimeFrames>, CandleSeries>(); 

		/// <summary>
		/// Создать <see cref="SmartCandleManagerSource"/>.
		/// </summary>
		/// <param name="trader">Шлюз к SmartCOM, через событие <see cref="SmartTrader.NewHistoryCandles"/> будут получаться свечки.</param>
		public SmartCandleManagerSource(SmartTrader trader)
		{
			if (trader == null)
				throw new ArgumentNullException("trader");

			Trader = trader;
			Trader.NewHistoryCandles += OnNewHistoryCandles;
		}

		/// <summary>
		/// Шлюз к SmartCOM, через событие <see cref="SmartTrader.NewHistoryCandles"/> будут получаться свечки.
		/// </summary>
		public SmartTrader Trader { get; private set; }

		private Action<CandleSeries, Candle> _processing;

		/// <summary>
		/// Приоритет источника по скорости (0 - самый оптимальный).
		/// </summary>
		public int SpeedPriority
		{
			get { return 1; }
		}

		event Action<CandleSeries, Candle> ICandleSource<Candle>.Processing
		{
			add { _processing += value; }
			remove { _processing -= value; }
		}

		//private Action<CandleSeries> _stopped;

		event Action<CandleSeries> ICandleSource<Candle>.Stopped
		{
			add { }
			remove { }
		}

		event Action<Exception> ICandleSource<Candle>.ProcessDataError
		{
			add { }
			remove { }
		}

		IEnumerable<Range<DateTime>> ICandleSource<Candle>.GetSupportedRanges(CandleSeries series)
		{
			if (series.CandleType == typeof(TimeFrameCandle) &&
				ReferenceEquals(series.Security.Trader, Trader) &&
				series.Arg is TimeSpan && SmartTimeFrames.CanConvert((TimeSpan)series.Arg))
			{
				yield return new Range<DateTime>(DateTime.MinValue, series.GetMarketTime());
			}
		}

		void ICandleSource<Candle>.Start(CandleSeries series, DateTime from, DateTime to)
		{
			if (series == null)
				throw new ArgumentNullException("series");

			if (series.CandleType != typeof(TimeFrameCandle))
				throw new ArgumentException("SmartCOM не поддерживает свечки типа {0}.".Put(series.CandleType), "series");

			if (!(series.Arg is TimeSpan))
				throw new ArgumentException("Неправильный параметр свечки {0}.".Put(series.Arg), "series");

			SmartTimeFrames tf = (TimeSpan)series.Arg;

			_series.Add(tf.GetToken(series.Security), series);

			Trader.RegisterHistoryRealTimeCandles(series.Security, tf, from);
		}

		void ICandleSource<Candle>.Stop(CandleSeries series)
		{
			if (series == null)
				throw new ArgumentNullException("series");

			Trader.UnRegisterHistoryRealTimeCandles(series.Security, (TimeSpan)series.Arg);
		}

		private void OnNewHistoryCandles(IEnumerable<TimeFrameCandle> candles)
		{
			var first = candles.First();

			var series = _series.TryGetValue(((SmartTimeFrames)first.TimeFrame).GetToken(first.Security));

			if (series == null)
				return;

			foreach (var candle in candles)
			{
				candle.State = CandleStates.Started;
				_processing.SafeInvoke(series, candle);

				candle.State = CandleStates.Finished;
				_processing.SafeInvoke(series, candle);
			}
		}

		/// <summary>
		/// Освободить ресурсы.
		/// </summary>
		protected override void DisposeManaged()
		{
			base.DisposeManaged();
			Trader.NewHistoryCandles -= OnNewHistoryCandles;
		}

		ICandleManager ICandleManagerSource.CandleManager { get; set; }
	}
}